back to index.

Rectcut in Haxe

I implemented RectCut in Haxe.

I've been working in Go/Typescript for the last few years, and most of my personal projects have been Go since then. Really a great language. But in the last few months I've been getting the eye back in with Haxe, finishing off some projects I started a long time ago. As part of one of them (which maybe I'll talk about some time), I was writing UI layout code. There's a lot of ways to approach this, and honestly, a lot of it is overkill when yo know the shape of what you're trying to accomplish. I'm not building a general purpose layout engine, I'm specifically building a handful of menus and UIs that fit pretty squarely into static-ish layouts. But they should still be relative, screen sizes change etc.

A few weeks back I read the RectCut article above. It's a smart idea - there's actually very little primitives needed to build a basic UI. Very inspired by immediate mode GUIs. And also a good fit for what I was writing. I spent ~an hour implementing it in Haxe. The code I'm sharing is library agnostic, but I'm using it with HaxeFlixel (crazy to return to Flixel 15 years after I last touched it). Haxe is still a great language - the Actionscript 3 follow on that everyone needs.

package; typedef RectCutRectangle = { var minX:Float; var minY:Float; var maxX:Float; var maxY:Float; } class RectCut { public static function GetRectangle(width:Float, height:Float, x:Float, y:Float):RectCutRectangle { return { minX: x - width / 2, maxX: x + width / 2, minY: y - height / 2, maxY: y + height / 2 }; } public static function CutLeft(rect:RectCutRectangle, width:Float):RectCutRectangle { var minX = rect.minX; rect.minX = Math.max(rect.minX, rect.minX + width); return { minX: minX, minY: rect.minY, maxX: rect.minX, maxY: rect.maxY }; } public static function CutRight(rect:RectCutRectangle, width:Float):RectCutRectangle { var maxX = rect.maxX; rect.maxX = Math.min(rect.maxX, rect.maxX - width); return { minX: rect.maxX, minY: rect.minY, maxX: maxX, maxY: rect.maxY }; } public static function CutTop(rect:RectCutRectangle, height:Float):RectCutRectangle { var minY = rect.minY; rect.minY = Math.max(rect.minY, rect.minY + height); return { minX: rect.minX, minY: minY, maxX: rect.maxX, maxY: rect.minY }; } public static function CutBottom(rect:RectCutRectangle, height:Float):RectCutRectangle { var maxY = rect.maxY; rect.maxY = Math.min(rect.maxY, rect.maxY - height); return { minX: rect.minX, minY: rect.maxY, maxX: rect.maxX, maxY: maxY }; } public static function AddTop(rect:RectCutRectangle, height:Float):RectCutRectangle { var minY = rect.minY - height; return { minX: rect.minX, minY: minY, maxX: rect.maxX, maxY: rect.minY }; } }

Sample usage

And here's a basic example of how I'm using it:

uiLayoutRect = RectCut.GetRectangle(120, 200, FlxG.width / 2, FlxG.height / 2); topRect = RectCut.CutTop(uiLayoutRect, 60); leftRect = RectCut.CutLeft(uiLayoutRect, 20); rightRect = RectCut.CutRight(uiLayoutRect, 20); bottomRect = RectCut.CutBottom(uiLayoutRect, 20); var titleText = new FlxSprite(); titleText.loadGraphic(AssetPaths.menutitle__png, false, 750, 295); titleText.scale.set(0.2, 0.2); titleText.updateHitbox(); var diffX = titleText.width - (topRect.maxX - topRect.minX); var rectCenterX = topRect.minX - (diffX / 2); var rectCenterY = topRect.minY; titleText.x = rectCenterX; titleText.y = rectCenterY; add(titleText); var playRect = RectCut.CutTop(uiLayoutRect, 20); playButton = new FlxButton(playRect.minX, playRect.minY, "Play", handlePlayClicked); add(playButton); // spacing - this can RectCut.CutTop(uiLayoutRect, 4); var exitRect = RectCut.CutTop(uiLayoutRect, 20); var exitButton = new FlxButton(exitRect.minX, exitRect.minY, "Exit", handlePlayClicked); add(exitButton);